#include <memory>
#include "Network/Client.h"
#include "Network/PackageManager.h"
#include "Network/Packages/PlayerDataPackage.h"
#include "Network/IPackage.hpp"

#include "Player/PlayerData.h"
#include "Subsystems/SubsystemPlayers.h"

#include "Log.h"
#include "Utils/BinaryIO.h"

#include "LiteNetLib/NetUtils.h"
#include "GameSingleton.h"


using namespace PocketSurvival::Engine;

namespace PocketSurvival
{

    Client::Client(NetPeerPtr theNetPeerPtr, const GameGuid &theGuid, uint8_t theClientID, const std::string &theNickname) : 
        m_loadtime(0),
        netPeer(theNetPeerPtr),
        guid(theGuid),
        clientID(theClientID),
        nickname(theNickname),
        playerData(nullptr), 
        state(ClientState::Connected)
    {
        m_ip = NetUtils::GetSockIP(theNetPeerPtr->getEndpoint());

        confusionGuid.createRandom();
    }

    Client::~Client() {}

    void Client::update(float dt)
    {
        // 防止玩家恶意卡在玩家加载页面不进服务器
        if(isEntityLoad() == false)
        {
            m_loadtime += dt;
            if(m_loadtime > 15.0f)
            {
                disconnect("加载玩家超时");
            }
        }

        m_waitHandlePackageMutex.lock();
        m_waitHandlePackageVecCatch.swap(m_waitHandlePackageVec);
        m_waitHandlePackageMutex.unlock();

        for (std::shared_ptr<IPackage> &package : m_waitHandlePackageVecCatch)
        {
            package->handle();
        }
        m_waitHandlePackageVecCatch.clear();



        if (m_abnormalCount > 0)
        {
            m_abnormalDecTime += dt;
            if (m_abnormalDecTime > 1.0f)
            {
                m_abnormalDecTime = 0;
                m_abnormalCount--;
            }
            if (m_abnormalCount > 50)
            {
                disconnect("异常次数过多");
            }
        }
    }

    bool Client::isEntityLoad()
    {
        if(playerData != nullptr && playerData->entity != entt::null)
        {
            return true;
        }
        return false;
    }

    void Client::disconnect(const std::string& message)
    {
        if (message.length() == 0)
        {
            netPeer->disconnect();
        }
        else
        {
            Utils::DynamicBinaryWriter writer(message.length() + 4);
            writer.writeSizeString(message);
            netPeer->disconnect(writer.getBuffer(), writer.getBuffSize());
        }
    }

    void Client::handleDisconnected()
    {
        if (playerData != nullptr)
        {
            GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>()->removePlayer(playerData);
            playerData = nullptr;
        }
    }

    void Client::addWaitHandlePackage(std::shared_ptr<IPackage> &package)
    {
        m_waitHandlePackageMutex.lock();
        m_waitHandlePackageVec.push_back(package);
        m_waitHandlePackageMutex.unlock();
    }

    void Client::createPlayerDataUseMsgJson(const nlohmann::json &jsonData)
    {
        playerData = std::make_shared<PlayerData>(shared_from_this());
        playerData->playerGuid = guid;
        playerData->username = nickname;
        playerData->loadMsgPackJson(jsonData);
        GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>()->addPlayer(playerData);

        std::shared_ptr<PlayerDataPackage> newPackage = std::make_shared<PlayerDataPackage>(playerData, PlayerDataPackageType::AddPlayer);
        newPackage->sendType = PackageSendType::TARGET;
        newPackage->client = shared_from_this();
        GameSingleton::packageManager->addSendPackageToQueue(newPackage);
    }

    void Client::loadPlayerData(const nlohmann::json &jsonData)
    {
        playerData = std::make_shared<PlayerData>(shared_from_this());
        playerData->playerGuid = guid;
        playerData->username = nickname;
        playerData->load(jsonData);
        GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>()->addPlayer(playerData);
    }
}
